<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能语音对话系统</title>
    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
    <style>
        :root {
            --primary-color: #00ff9d;
            --secondary-color: #00b4ff;
            --dark-bg: #0a192f;
            --darker-bg: #020c1b;
            --text-color: #e6f1ff;
            --highlight-color: #ff2d75;
        }
        
        body {
            font-family: 'Roboto', sans-serif;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            background-color: var(--dark-bg);
            color: var(--text-color);
            background-image: 
                radial-gradient(circle at 25% 25%, rgba(0, 180, 255, 0.1) 0%, transparent 50%),
                radial-gradient(circle at 75% 75%, rgba(0, 255, 157, 0.1) 0%, transparent 50%);
        }
        
        h1 {
            font-family: 'Orbitron', sans-serif;
            font-weight: 700;
            color: var(--primary-color);
            text-shadow: 0 0 10px rgba(0, 255, 157, 0.5);
            margin-bottom: 10px;
            letter-spacing: 1px;
        }
        
        .container {
            background-color: var(--darker-bg);
            border-radius: 15px;
            padding: 25px;
            margin-top: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            border: 1px solid rgba(0, 180, 255, 0.2);
            position: relative;
            overflow: hidden;
        }
        
        .container::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
        }
        
        .status-container {
            position: relative;
            margin: 30px 0;
            padding: 20px;
            border-radius: 10px;
            background-color: rgba(0, 25, 47, 0.7);
            border: 1px solid rgba(0, 180, 255, 0.3);
            box-shadow: inset 0 0 15px rgba(0, 180, 255, 0.1);
        }
        
        .status {
            font-size: 24px;
            font-weight: bold;
            margin: 0;
            font-family: 'Orbitron', sans-serif;
            position: relative;
            z-index: 2;
        }
        
        .status-indicator {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            opacity: 0.1;
            border-radius: 8px;
            transition: background-color 0.3s ease;
        }
        
        .listening .status-indicator {
            background-color: var(--primary-color);
            animation: pulse 2s infinite;
        }
        
        .processing .status-indicator {
            background-color: var(--secondary-color);
            animation: pulse 1.5s infinite;
        }
        
        .speaking .status-indicator {
            background-color: var(--highlight-color);
            animation: pulse 1s infinite;
        }
        
        @keyframes pulse {
            0% { opacity: 0.1; }
            50% { opacity: 0.3; }
            100% { opacity: 0.1; }
        }
        
        #audioWave {
            width: 100%;
            height: 120px;
            margin: 30px 0;
            background-color: rgba(0, 25, 47, 0.7);
            border-radius: 10px;
            border: 1px solid rgba(0, 180, 255, 0.3);
            position: relative;
            overflow: hidden;
        }
        
        .waveform {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0 20px;
        }
        
        .wave-bar {
            width: 6px;
            height: 20px;
            margin: 0 3px;
            background: linear-gradient(to top, var(--primary-color), var(--secondary-color));
            border-radius: 3px;
            animation: wave 1.5s infinite ease-in-out;
            transform-origin: bottom;
        }
        
        @keyframes wave {
            0%, 100% { transform: scaleY(0.3); }
            50% { transform: scaleY(1); }
        }
        
        .wave-bar:nth-child(1) { animation-delay: 0.1s; }
        .wave-bar:nth-child(2) { animation-delay: 0.2s; }
        .wave-bar:nth-child(3) { animation-delay: 0.3s; }
        .wave-bar:nth-child(4) { animation-delay: 0.4s; }
        .wave-bar:nth-child(5) { animation-delay: 0.5s; }
        .wave-bar:nth-child(6) { animation-delay: 0.4s; }
        .wave-bar:nth-child(7) { animation-delay: 0.3s; }
        .wave-bar:nth-child(8) { animation-delay: 0.2s; }
        .wave-bar:nth-child(9) { animation-delay: 0.1s; }
        
        .btn-group {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin: 30px 0;
        }
        
        button {
            position: relative;
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: var(--darker-bg);
            border: none;
            padding: 12px 30px;
            font-size: 16px;
            font-weight: 500;
            margin: 10px 0;
            cursor: pointer;
            border-radius: 50px;
            font-family: 'Orbitron', sans-serif;
            letter-spacing: 1px;
            overflow: hidden;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(0, 255, 157, 0.3);
        }
        
        button:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(0, 255, 157, 0.4);
        }
        
        button:active {
            transform: translateY(1px);
        }
        
        button:disabled {
            background: #555;
            color: #999;
            cursor: not-allowed;
            box-shadow: none;
            transform: none;
        }
        
        button::after {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: rgba(255, 255, 255, 0.1);
            transform: rotate(45deg);
            transition: all 0.3s ease;
            opacity: 0;
        }
        
        button:hover::after {
            opacity: 1;
            top: -20%;
            left: -20%;
        }
        
        .conversation-container {
            display: flex;
            flex-direction: column;
            gap: 20px;
            margin: 30px 0;
        }
        
        .conversation, .log {
            text-align: left;
            border-radius: 10px;
            background-color: rgba(0, 25, 47, 0.7);
            border: 1px solid rgba(0, 180, 255, 0.3);
            box-shadow: inset 0 0 15px rgba(0, 180, 255, 0.1);
            padding: 20px;
            max-height: 250px;
            overflow-y: auto;
        }
        
        .conversation-title, .log-title {
            font-family: 'Orbitron', sans-serif;
            color: var(--primary-color);
            margin-top: 0;
            margin-bottom: 15px;
            font-size: 18px;
            display: flex;
            align-items: center;
        }
        
        .conversation-title::before, .log-title::before {
            content: '';
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: var(--primary-color);
            margin-right: 10px;
            box-shadow: 0 0 5px var(--primary-color);
        }
        
        .log-title::before {
            background-color: var(--secondary-color);
            box-shadow: 0 0 5px var(--secondary-color);
        }
        
        .message {
            margin: 10px 0;
            padding: 12px 15px;
            border-radius: 8px;
            position: relative;
            line-height: 1.5;
            animation: fadeIn 0.3s ease;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        .user-message {
            background-color: rgba(0, 180, 255, 0.15);
            border-left: 3px solid var(--secondary-color);
            margin-left: 20px;
        }
        
        .ai-message {
            background-color: rgba(0, 255, 157, 0.15);
            border-left: 3px solid var(--primary-color);
            margin-right: 20px;
        }
        
        .message-sender {
            font-weight: bold;
            margin-bottom: 5px;
            font-family: 'Orbitron', sans-serif;
            font-size: 14px;
        }
        
        .user-message .message-sender {
            color: var(--secondary-color);
        }
        
        .ai-message .message-sender {
            color: var(--primary-color);
        }
        
        .log-entry {
            margin: 8px 0;
            padding: 8px 0;
            border-bottom: 1px solid rgba(0, 180, 255, 0.1);
            font-size: 13px;
            color: #a8b2d1;
            display: flex;
        }
        
        .log-time {
            color: var(--secondary-color);
            margin-right: 10px;
            font-family: 'Orbitron', sans-serif;
            font-size: 12px;
            min-width: 70px;
        }
        
        .typing-indicator {
            display: flex;
            align-items: center;
            padding: 10px 15px;
            background-color: rgba(0, 255, 157, 0.1);
            border-radius: 8px;
            margin: 10px 0;
            width: fit-content;
        }
        
        .typing-dot {
            width: 8px;
            height: 8px;
            background-color: var(--primary-color);
            border-radius: 50%;
            margin: 0 3px;
            animation: typingAnimation 1.4s infinite ease-in-out;
        }
        
        .typing-dot:nth-child(1) { animation-delay: 0s; }
        .typing-dot:nth-child(2) { animation-delay: 0.2s; }
        .typing-dot:nth-child(3) { animation-delay: 0.4s; }
        
        @keyframes typingAnimation {
            0%, 60%, 100% { transform: translateY(0); }
            30% { transform: translateY(-5px); }
        }
        
        /* 自定义滚动条 */
        ::-webkit-scrollbar {
            width: 8px;
        }
        
        ::-webkit-scrollbar-track {
            background: rgba(0, 0, 0, 0.2);
            border-radius: 4px;
        }
        
        ::-webkit-scrollbar-thumb {
            background: linear-gradient(var(--primary-color), var(--secondary-color));
            border-radius: 4px;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            body {
                padding: 10px;
            }
            
            .container {
                padding: 15px;
            }
            
            .btn-group {
                flex-direction: column;
                gap: 10px;
            }
            
            button {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <h1>智能语音对话系统</h1>
    <p>请允许麦克风访问权限，开始与AI对话</p>
  
    <div class="container">
        <div class="status-container">
            <div id="status" class="status">等待语音输入...</div>
            <div id="statusIndicator" class="status-indicator"></div>
        </div>
      
        <div id="audioWave">
            <div class="waveform">
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
                <div class="wave-bar"></div>
            </div>
        </div>
      
        <div class="btn-group">
            <button id="startBtn">
                <span>启动对话</span>
            </button>
            <button id="stopBtn" disabled>
                <span>结束对话</span>
            </button>
        </div>
      
        <div class="conversation-container">
            <div class="conversation" id="conversation">
                <h3 class="conversation-title">对话记录</h3>
                <div id="conversationContent"></div>
            </div>
          
            <div class="log" id="eventLog">
                <h3 class="log-title">系统日志</h3>
                <div id="logContent"></div>
            </div>
        </div>
    </div>

    <!-- 加载必要的库 -->
    <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.14.0/dist/ort.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.22/dist/bundle.min.js"></script>
  
    <script>
        // 全局变量
        let myvad = null;
        let audioContext = null;
        let isProcessing = false;
        let isVADPaused = false;
        let waveBars = [];
        
        // API配置
        const apiConfig = {
            apiUrl: window.location.origin, // 使用当前域名作为API的基础URL
            processingEndpoint: '/process_audio',
            debug: true
        };
        
        // 初始化页面元素
        document.addEventListener('DOMContentLoaded', () => {
            waveBars = Array.from(document.querySelectorAll('.wave-bar'));
            updateWaveform(0); // 初始化为静音状态
        });
        
        // 更新波形显示
        function updateWaveform(level) {
            waveBars.forEach((bar, index) => {
                // 根据语音活动级别和条形位置计算高度
                const positionFactor = 1 - Math.abs(index - 4) / 4; // 中间条形更高
                const heightFactor = level * 0.8 + 0.2; // 确保最小高度
                const scale = positionFactor * heightFactor;
                bar.style.transform = `scaleY(${scale})`;
                
                // 根据高度调整颜色
                const colorValue = Math.min(255, 100 + scale * 155);
                bar.style.background = `linear-gradient(to top, 
                    rgba(0, 255, 157, ${scale}), 
                    rgba(0, 180, 255, ${scale}))`;
            });
        }
        
        // 模拟波形动画
        function simulateWaveform() {
            let level = 0;
            const interval = setInterval(() => {
                if (isProcessing || isVADPaused) {
                    level = Math.max(0, level - 0.05);
                } else {
                    // 随机波动，模拟环境噪音
                    level = Math.min(1, Math.max(0, level + (Math.random() - 0.5) * 0.2));
                }
                updateWaveform(level);
            }, 100);
            
            return interval;
        }
        
        let waveInterval = simulateWaveform();
        
        // 将Blob转换为Base64
        function blobToBase64(blob) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onloadend = () => {
                    // 移除data URL前缀
                    const base64 = reader.result.split(',')[1];
                    resolve(base64);
                };
                reader.onerror = reject;
                reader.readAsDataURL(blob);
            });
        }
        
        // 将音频发送到服务器处理
        async function processAudio(audioBlob, options = {}) {
            if (!audioBlob) {
                addLog("错误: 没有音频数据");
                return Promise.reject(new Error('没有音频数据'));
            }

            try {
                // 将Blob转换为Base64
                const base64Audio = await blobToBase64(audioBlob);
                addLog(`音频转换为Base64完成，大小: ${base64Audio.length} 字符`);
                
                // 准备请求数据
                const requestData = {
                    audio_data: base64Audio,
                    text_prompt: options.prompt || '这段音频在说什么'
                };

                addLog(`发送请求到API: ${apiConfig.apiUrl}${apiConfig.processingEndpoint}`);
                
                // 发送请求，添加超时处理
                const timeout = 120000; // 120秒超时
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), timeout);

                const response = await fetch(`${apiConfig.apiUrl}${apiConfig.processingEndpoint}`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(requestData),
                    signal: controller.signal
                });
                
                clearTimeout(timeoutId);
                
                if (!response.ok) {
                    throw new Error(`HTTP错误! 状态: ${response.status}`);
                }
                
                const result = await response.json();
                addLog(`收到API响应: 文本长度: ${result.text.length} 字符`);
                
                if (result.audio) {
                    addLog(`收到音频响应，大小: ${result.audio.length} 字符`);
                }
                
                return result;
            } catch (error) {
                addLog(`处理音频请求出错: ${error.message}`);
                if (error.name === 'AbortError') {
                    throw new Error('请求超时');
                }
                throw error;
            }
        }
        
        // 播放Base64编码的音频
        function playAudio(base64Audio) {
            return new Promise((resolve, reject) => {
                try {
                    // 创建一个audio元素
                    const audio = new Audio();
                    
                    // 监听播放结束事件
                    audio.addEventListener('ended', () => {
                        addLog("音频播放完成");
                        resolve();
                    });
                    audio.addEventListener('error', (e) => {
                        addLog(`音频播放错误: ${e.message}`);
                        reject(e);
                    });
                    
                    // 设置音频源
                    audio.src = `data:audio/wav;base64,${base64Audio}`;
                    
                    // 播放音频
                    audio.play().catch(e => {
                        addLog(`播放音频失败: ${e.message}`);
                        reject(e);
                    });
                } catch (error) {
                    addLog(`音频播放设置失败: ${error.message}`);
                    reject(error);
                }
            });
        }
        
        // 初始化VAD
        async function initVAD() {
            try {
                myvad = await vad.MicVAD.new({
                    onSpeechStart: () => {
                        if (!isProcessing && !isVADPaused) {
                            updateStatus("正在聆听...", "listening");
                            addLog("检测到语音开始");
                            
                            // 激活波形显示
                            waveBars.forEach(bar => {
                                bar.style.animationPlayState = 'running';
                            });
                        }
                    },
                    onSpeechEnd: async (audio) => {
                        if (isProcessing || isVADPaused) return;
                        isProcessing = true;
                        updateStatus("处理中...", "processing");
                        addLog("检测到语音结束");
                        
                        // 显示正在输入指示器
                        showTypingIndicator();
                        
                        // 暂停VAD而不是停止
                        try {
                            if (myvad && typeof myvad.pause === 'function') {
                                await myvad.pause();
                                isVADPaused = true;
                                addLog("VAD已暂停");
                            }
                        } catch (e) {
                            console.error("暂停VAD时出错:", e);
                            addLog(`错误: 暂停VAD失败 - ${e.message}`);
                        }
                        
                        try {
                            // 将WebRTC音频数据转换为Blob
                            const audioBlob = new Blob([audio.audioData], { type: 'audio/webm' });
                            addLog(`音频长度: ${audio.audioData.byteLength} 字节`);
                            
                            // 将用户语音转写添加到对话
                            if (audio.transcript) {
                                addConversation('user', audio.transcript);
                            } else {
                                addConversation('user', '(语音内容不可获取)');
                            }
                            
                            // 发送到API处理
                            const result = await processAudio(audioBlob, {
                                prompt: "这段音频在说什么，请用中文回复"
                            });
                            
                            // 隐藏正在输入指示器
                            hideTypingIndicator();
                            
                            // 添加AI响应到对话
                            addConversation('ai', result.text);
                            
                            // 如果有音频响应，播放它
                            if (result.audio) {
                                await playAIResponse(result.audio);
                            } else {
                                // 如果没有音频，使用浏览器的TTS
                                updateStatus("AI正在说话...", "speaking");
                                await playTextAudio(result.text);
                                updateStatus("等待语音输入...", "");
                            }
                            
                            // 播放完成后恢复VAD
                            resumeVAD();
                        } catch (error) {
                            console.error("处理音频时出错:", error);
                            addLog(`错误: ${error.message}`);
                            hideTypingIndicator();
                            addConversation('ai', "很抱歉，处理您的请求时出错。请再试一次。");
                            resumeVAD();
                        }
                    },
                    // 其他VAD配置参数
                    positiveSpeechThreshold: 0.70,
                    negativeSpeechThreshold: 0.50,
                    model: "v5",
                });
                
                // 启动VAD
                await myvad.start();
                isVADPaused = false;
                addLog("VAD已启动");
            } catch (error) {
                console.error("VAD初始化失败:", error);
                addLog(`错误: VAD初始化失败 - ${error.message}`);
            }
        }
        
        // 显示正在输入指示器
        function showTypingIndicator() {
            const conversationContent = document.getElementById('conversationContent');
            const typingDiv = document.createElement('div');
            typingDiv.className = 'typing-indicator';
            typingDiv.id = 'typingIndicator';
            
            for (let i = 0; i < 3; i++) {
                const dot = document.createElement('div');
                dot.className = 'typing-dot';
                typingDiv.appendChild(dot);
            }
            
            conversationContent.appendChild(typingDiv);
            conversationContent.scrollTop = conversationContent.scrollHeight;
        }
        
        // 隐藏正在输入指示器
        function hideTypingIndicator() {
            const typingIndicator = document.getElementById('typingIndicator');
            if (typingIndicator) {
                typingIndicator.remove();
            }
        }
        
        // 恢复VAD监听
        async function resumeVAD() {
            if (!myvad || !isVADPaused) return;
            try {
                // 某些VAD实现可能需要重新初始化而不是简单的start
                if (typeof myvad.start === 'function') {
                    await myvad.start();
                    isVADPaused = false;
                    isProcessing = false;
                    updateStatus("等待语音输入...", "listening");
                    addLog("VAD已恢复");
                }
            } catch (e) {
                console.error("恢复VAD时出错:", e);
                addLog(`错误: 恢复VAD失败 - ${e.message}`);
              
                // 失败时尝试重新初始化
                await initVAD();
            }
        }
        
        // 播放AI响应从服务器返回的音频
        async function playAIResponse(base64Audio) {
            updateStatus("AI正在说话...", "speaking");
            addLog("开始播放AI响应音频");
            
            // 模拟波形活动
            let speakingInterval = setInterval(() => {
                const level = 0.5 + Math.random() * 0.5;
                updateWaveform(level);
            }, 100);
            
            try {
                await playAudio(base64Audio);
                addLog("AI响应音频播放完成");
            } catch (error) {
                addLog(`播放音频失败: ${error.message}`);
            } finally {
                clearInterval(speakingInterval);
                updateWaveform(0);
                updateStatus("等待语音输入...", "");
            }
        }
        
        // 使用浏览器的语音合成播放文本
        async function playTextAudio(text) {
            addLog("使用浏览器语音合成播放文本");
            
            // 模拟波形活动
            let speakingInterval = setInterval(() => {
                const level = 0.5 + Math.random() * 0.5;
                updateWaveform(level);
            }, 100);
            
            return new Promise((resolve) => {
                if ('speechSynthesis' in window) {
                    const utterance = new SpeechSynthesisUtterance(text);
                    
                    // 设置声音参数
                    utterance.volume = 1.0;
                    utterance.rate = 1.0;
                    utterance.pitch = 1.0;
                    utterance.lang = 'zh-CN';
                    
                    utterance.onstart = () => {
                        addLog("语音合成开始播放");
                    };
                    
                    utterance.onend = () => {
                        clearInterval(speakingInterval);
                        updateWaveform(0);
                        addLog("AI响应播放完成");
                        resolve();
                    };
                    
                    utterance.onerror = (event) => {
                        addLog(`语音合成错误: ${event.error}`);
                        clearInterval(speakingInterval);
                        updateWaveform(0);
                        resolve();
                    };
                    
                    // 在iOS上，需要先暂停再重启语音合成
                    window.speechSynthesis.cancel();
                    
                    // 解决iOS上需要用户交互的问题
                    setTimeout(() => {
                        try {
                            window.speechSynthesis.speak(utterance);
                            
                            // iOS Safari需要保持语音合成活跃
                            if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
                                const iosInterval = setInterval(() => {
                                    if (!window.speechSynthesis.speaking) {
                                        clearInterval(iosInterval);
                                        return;
                                    }
                                    window.speechSynthesis.pause();
                                    window.speechSynthesis.resume();
                                }, 10000);
                            }
                        } catch (e) {
                            addLog(`语音合成异常: ${e.message}`);
                            clearInterval(speakingInterval);
                            updateWaveform(0);
                            resolve();
                        }
                    }, 100);
                } else {
                    addLog("没有语音合成API");
                    // 如果没有语音合成API，模拟延迟
                    setTimeout(() => {
                        clearInterval(speakingInterval);
                        updateWaveform(0);
                        resolve();
                    }, 2000);
                }
            });
        }
        
        // 启动对话
        async function startConversation() {
            try {
                // 初始化音频上下文
                if (!audioContext) {
                    audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    addLog("音频上下文已初始化");
                    
                    // iOS需要在用户交互中解锁AudioContext
                    if (audioContext.state === 'suspended') {
                        audioContext.resume();
                    }
                }
                
                // 初始化语音合成
                if ('speechSynthesis' in window) {
                    // 在用户交互时预热语音合成引擎
                    window.speechSynthesis.cancel();
                    const utterance = new SpeechSynthesisUtterance('');
                    window.speechSynthesis.speak(utterance);
                }
                
                // 初始化VAD
                await initVAD();
                
                // 更新UI状态
                startBtn.disabled = true;
                stopBtn.disabled = false;
                updateStatus("等待语音输入...", "listening");
                
                // 添加欢迎消息
                addConversation('ai', '您好！我是智能语音助手，请开始说话...');
            } catch (error) {
                console.error("启动失败:", error);
                addLog(`错误: ${error.message}`);
                updateStatus("启动失败", "error");
            }
        }
        
        // 停止对话
        async function stopConversation() {
            try {
                if (myvad) {
                    // 不同VAD实现可能有不同方法
                    if (typeof myvad.destroy === 'function') {
                        await myvad.destroy();
                    } else if (typeof myvad.stop === 'function') {
                        await myvad.stop();
                    }
                    addLog("VAD已停止");
                }
                
                if (audioContext && audioContext.state !== 'closed') {
                    await audioContext.close();
                    addLog("音频上下文已关闭");
                }
                
                // 重置状态
                myvad = null;
                audioContext = null;
                isProcessing = false;
                isVADPaused = false;
                
                // 更新UI
                startBtn.disabled = false;
                stopBtn.disabled = true;
                updateStatus("对话已结束", "");
                updateWaveform(0);
                
                // 添加结束消息
                addConversation('ai', '对话已结束。如需继续，请点击"启动对话"按钮。');
            } catch (error) {
                console.error("停止时出错:", error);
                addLog(`错误: ${error.message}`);
            }
        }
        
        // 更新状态显示
        function updateStatus(text, state) {
            const statusElement = document.getElementById('status');
            const indicator = document.getElementById('statusIndicator');
            
            statusElement.textContent = text;
            
            // 移除所有状态类
            statusElement.className = 'status';
            indicator.className = 'status-indicator';
            
            // 添加新状态类
            if (state) {
                statusElement.classList.add(state);
                indicator.classList.add(state);
            }
        }
        
        // 添加日志条目
        function addLog(message) {
            const logContent = document.getElementById('logContent');
            const now = new Date();
            const timeString = now.toLocaleTimeString();
            
            const logEntry = document.createElement('div');
            logEntry.className = 'log-entry';
            
            const timeSpan = document.createElement('span');
            timeSpan.className = 'log-time';
            timeSpan.textContent = timeString;
            
            const messageSpan = document.createElement('span');
            messageSpan.textContent = message;
            
            logEntry.appendChild(timeSpan);
            logEntry.appendChild(messageSpan);
            logContent.appendChild(logEntry);
            logContent.scrollTop = logContent.scrollHeight;
        }
        
        // 添加对话消息
        function addConversation(speaker, message) {
            const conversationContent = document.getElementById('conversationContent');
            const messageDiv = document.createElement('div');
            messageDiv.className = speaker === 'user' ? 'user-message message' : 'ai-message message';
            
            const senderDiv = document.createElement('div');
            senderDiv.className = 'message-sender';
            senderDiv.textContent = speaker === 'user' ? '你说' : 'AI助手';
            
            const textDiv = document.createElement('div');
            textDiv.textContent = message;
            
            messageDiv.appendChild(senderDiv);
            messageDiv.appendChild(textDiv);
            conversationContent.appendChild(messageDiv);
            conversationContent.scrollTop = conversationContent.scrollHeight;
        }
        
        // 事件监听
        document.getElementById('startBtn').addEventListener('click', startConversation);
        document.getElementById('stopBtn').addEventListener('click', stopConversation);
        
        // 页面卸载时清理
        window.addEventListener('beforeunload', () => {
            if (myvad || audioContext) {
                stopConversation();
            }
            if (waveInterval) {
                clearInterval(waveInterval);
            }
        });
    </script>
</body>
</html>